package packageServer;

public abstract class Dinosauro {

	private int id;
	private int dimensione;
	private int turnivissuti;
	private int energia;
	private int energia_max;
	private int posX;
	private int posY;	
	private int vita_max;
	
	//@requires id>=0;
	//@ensures dimensione==1;
	//@ensures energia==1000;
	//@ensures energia_max==1000;
	//@ensures ((vita_max>=24)&&(vita_max<=36));
    //@ensures turnivissuti==0;
	public Dinosauro(int id){
		this.id=id;
		dimensione=1;
		energia=1000;
		energia_max=1000;
		vita_max=24+((int)(Math.random()*12));
		turnivissuti=0;
			
	}
	
	
	/**
	 * Metodo che serve per invecchiare un dinosauro alla fine di ogni turno del suo utente.
	 * 
	 * @return Ritorna true se l'invecchiamento e' andato a buon fine, false se il dinosauro e'
	 * morto di vecchiaia.
	 */
	//@ensures ((turnivissuti==(\old(turnivissuti)+1)));
	//@requires turnivissuti>vita_max;
	//@ensures \result==false;
	//@also
	//@requires !(turnivissuti>vita_max);
	//@ensures \result==true;
	public boolean invecchia(){				
		turnivissuti++;
		if(turnivissuti>vita_max)
			return false;
		else
			return true;
	}	
	
	
	
	public int getVita_max() {
		return vita_max;
	}


	public void setVita_max(int vita_max) {
		this.vita_max = vita_max;
	}


	public int getPosX() {
		return posX;
	}

	
	
	public void setPosX(int posX) {
		this.posX = posX;
	}

	
	public int getPosY() {
		return posY;
	}

	
	
	public void setPosY(int posY) {
		this.posY = posY;
	}

	
	
	public int getDimensione() {
		return dimensione;
	}

	/**
	 * Metodo astratto per il calcolo della forza, implementato diversamente in erbivoro
	 * e carnivoro mediante overriding.
	 */
	public abstract int calcolaForza();
	

	public void setDimensione(int dimensione) {
		this.dimensione = dimensione;
		setEnergia_max(1000*dimensione);
	}

	
	public int getTurnivissuti() {
		return turnivissuti;
	}

	public void setTurnivissuti(int turnivissuti) {
		this.turnivissuti = turnivissuti;
	}

	
	public int getEnergia() {
		return energia;
	}

	

	public void setEnergia(int energia) {
		if(energia<this.energia_max)
			this.energia = energia;
		else
			this.energia=this.energia_max;
	}
	
	
		
	public int getEnergia_max() {
		return energia_max;
	}

	
	public void setEnergia_max(int energia_max) {
		this.energia_max = energia_max;
	}
	
	
	public void setId(int id) {
		this.id = id;
	}

	
	public int getId() {
		return id;
	}
	
	
	/**
	 * Effettua un controllo basato su come il calcolo della forza viene implementato, per capire se
	 * il tipo del dinosauro e' erbivoro oppure carnivoro.
	 *
	 * @return Ritorna true per indicare che un dinosauro e' erbivoro, false se e' carnivoro.
	 */
	public boolean controllaErbivoro(){
		if(calcolaForza()==this.energia*this.dimensione)
			return true;
		return false;
	}

	/**
	 * Effettua un controllo sulla mossa che si vuol far fare al dinosauro.
	 * Nel caso che la casella di destinazione sia troppo lontana, sia occupata, sia acqua
	 * o non sia raggiungibile, nega il permesso all'operazione.
	 * 
	 * @param map La mappa totale di gioco.
	 * @param newPosX La nuova coordinata di riga a cui si vuole mandare il dinosauro.
	 * @param newPosY La nuova coordinata di colonna a cui si vuole mandare il dinosauro.
	 * @return Ritorna false se la mossa non viene permessa, true se va bene.
	 */
	//@requires map!=null;
	//@requires (newPosX>=0)&&(newPosX<=39);
	//@requires (newPosY>=0)&&(newPosY<=39);
	public boolean controlloMossa( Mappa map, int newPosX, int newPosY){
		int maxMove;
		
		if(controllaErbivoro())
			maxMove=2;
		else
			maxMove=3;

		if(getPosX()-newPosX<-maxMove||getPosX()-newPosX>maxMove||getPosY()-newPosY<-maxMove||getPosY()-newPosY>maxMove)
				return false;
		if(controllaErbivoro())
			if(map.getCella(newPosX, newPosY).getDino()!=null)
				if(map.getCella(newPosX, newPosY).getDino().controllaErbivoro())
					return false;		
		if(map.getCella(newPosX, newPosY).getTipo().equals("a"))
			return false;
		
		return esistePercorso(newPosX,newPosY,maxMove, map);
	}
	
	
	/**
	 * Fa il controllo ricorsivo se esiste un percorso che dalla cella in cui si vuole andare
	 * porta al dinosauro che l'utente vuole far muovere.
	 * 
	 * @param newPosX La coordinata della riga della cella che si sta analizzando nella ricorsione.
	 * @param newPosY La coordinata della colonna della cella che si sta analizzando nella ricorsione.
	 * @param maxMove Movimento massimo ancora consentito al dinosauro.
	 * @param map Mappa generale di gioco.
	 * @return Ritorna false se non esiste la strada, true se esiste.
	 */
	//@requires map!=null;
	//@requires (newPosX>=0)&&(newPosX<=39);
	//@requires (newPosY>=0)&&(newPosY<=39);
	//@requires (maxMove>=0)&&(maxMove<=3);
	public boolean esistePercorso(int newPosX, int newPosY, int maxMove, Mappa map){
		int i,j;
		boolean trovato=false;
		
		if(maxMove==0)
			return false;
		
		maxMove--;
		
		for(i=(newPosX-1);i<=(newPosX+1);i++)
			for(j=(newPosY-1);j<=(newPosY+1);j++)
				if(i==getPosX()&&j==getPosY())
					return true;
					
				else{if(!map.getCella(i,j).getTipo().equals("a"))
						trovato=esistePercorso(i,j,maxMove,map);
					if(trovato==true)
						return trovato;
				}
		
		return false;
	}
	
}
